package suncertify.db;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import suncertify.db.exc.DuplicateKeyException;
import suncertify.db.exc.RecordNotFoundException;
import suncertify.db.exc.SecurityException;

public class Data implements DB {

    private static DataManager dataManager = null;

    private static LockManager lockManager = new LockManager();

    private static Data instance = new Data();

    /** Map that stores all the valid records, the key is the record number */
    private Map<Integer, String[]> roomMap = new HashMap<Integer, String[]>();

    /** The database file location */
    // private String databaseLocation =
    // "D:\\Entwicklung\\SCJD\\Certification\\Aufgabe\\File\\db-1x1.db";
    // private static final String DATABASE_LOCATION =
    // "D:\\Entwicklung\\SCJD\\Certification\\Aufgabe\\File\\db-1x1.db";

    /** Character Encoding */
    private static final String ENCODING = "US-ASCII";

    /** The value that identifies a record as being valid */
    private static final int VALID = 0;

    /** The bytes that store the length of each field name */
    private static final int FIELD_NAME_BYTES = 2;
    /** The bytes that store the fields length */
    private static final int FIELD_LENGTH_BYTES = 2;

    /** The length of the header in the file */
    private static int HEADER_LENGTH;

    /** The length of one record in the file */
    private static int RECORD_LENGTH;

    private Data() {

    }

    /**
     * Constructor for the standalone version. Pattern is a Singleton.
     * 
     * @return instance of Data
     * @throws RecordNotFoundException
     * @throws IOException 
     */
    public static Data getInstance() throws RecordNotFoundException, IOException {
	return getInstance("user.dir");
    }
    
    /**
     * Constructor with path as parameter. Pattern is a Singleton.
     * 
     * @param path
     * @return instance of data
     * @throws RecordNotFoundException 
     * @throws IOException 
     */
    public static Data getInstance(String path) throws RecordNotFoundException, IOException {
	dataManager = new DataManager(path);
	return instance;
    }

    @Override
    public String[] read(int recNo) throws RecordNotFoundException {
	return dataManager.read(recNo);
    }

    @Override
    public void update(int recNo, String[] data, long lockCookie)
	    throws RecordNotFoundException, SecurityException {
	// If the record to be updated doesn't exist, a RecordNotFoundException
	// is thrown
	if (!dataManager.checkRecordExists(recNo)) {
	    throw new RecordNotFoundException();
	}
	// Check if record is locked at all (!= null) and with given lockCookie
	if (!lockManager.checkLocked(recNo, lockCookie)) {
	    throw new SecurityException();
	}
	dataManager.update(recNo, data);
    }

    @Override
    public void delete(int recNo, long lockCookie)
	    throws RecordNotFoundException, SecurityException {
	// If the record to be deleted doesn't exist, a RecordNotFoundException
	// is thrown
	if (!dataManager.checkRecordExists(recNo)) {
	    throw new RecordNotFoundException();
	}

	// Check if record is locked at all (!= null) and with given lockCookie
	if (!lockManager.checkLocked(recNo, lockCookie)) {
	    throw new SecurityException();
	}

	dataManager.delete(recNo, lockCookie);
    }

    @Override
    public int[] find(String[] criteria) {
	return dataManager.find(criteria);
    }

    @Override
    public int create(String[] data) throws DuplicateKeyException {
	return dataManager.create(data);
    }

    @Override
    public long lock(int recNo) throws RecordNotFoundException {
	// If the record to be locked doesn't exist, a RecordNotFoundException
	// is thrown
	if (!dataManager.checkRecordExists(recNo)) {
	    throw new RecordNotFoundException();
	}
	return lockManager.lock(recNo);
    }

    @Override
    public void unlock(int recNo, long cookie) throws RecordNotFoundException,
	    SecurityException {
	// If the record to be unlocked doesn't exist, a RecordNotFoundException
	// is thrown
	if (!dataManager.checkRecordExists(recNo)) {
	    throw new RecordNotFoundException();
	}
	lockManager.unlock(recNo, cookie);
    }

    public Map<Integer, String[]> getRoomMap() {
	return roomMap;
    }

}
